#include "public.h"

EXTERN_C_START

#define MAX_EVENTS 32

#pragma align(push, 4)
typedef struct IVSHMEMDeviceRegisters
{
    volatile ULONG irqMask;
    volatile ULONG irqStatus;
    volatile LONG ivProvision;
    volatile ULONG doorbell;
    volatile UCHAR reserved[240];
} IVSHMEMDeviceRegisters, *PIVSHMEMDeviceRegisters;
#pragma align(pop)

typedef struct IVSHMEMEventListEntry
{
    WDFFILEOBJECT owner;
    UINT16 vector;
    PRKEVENT event;
    BOOLEAN singleShot;
    LIST_ENTRY ListEntry;
} IVSHMEMEventListEntry, *PIVSHMEMEventListEntry;

#if (NTDDI_VERSION < NTDDI_WIN8)
typedef struct _MM_PHYSICAL_ADDRESS_LIST
{
    PHYSICAL_ADDRESS PhysicalAddress;
    PVOID VirtualAddress;
    SIZE_T NumberOfBytes;
} MM_PHYSICAL_ADDRESS_LIST, *PMM_PHYSICAL_ADDRESS_LIST;
#endif

typedef struct _DEVICE_CONTEXT
{
    PIVSHMEMDeviceRegisters devRegisters; // the device registers (BAR0)

    MM_PHYSICAL_ADDRESS_LIST shmemAddr; // physical address of the shared memory (BAR2)
    PMDL shmemMDL;                      // memory discriptor list of the shared memory
    UINT16 interruptCount;              // the number of interrupt entries allocated
    UINT16 interruptsUsed;              // the number of interrupt entries used
    WDFINTERRUPT *interrupts;           // interrupts for this device
    LONG64 pendingISR;                  // flags for ISRs pending processing

    KSPIN_LOCK eventListLock;                      // spinlock for the below event list
    IVSHMEMEventListEntry eventBuffer[MAX_EVENTS]; // buffer of pre-allocated events
    UINT16 eventBufferUsed;                        // number of events currenty in use
    LIST_ENTRY eventList;                          // pending events to fire
} DEVICE_CONTEXT, *PDEVICE_CONTEXT;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, DeviceGetContext)

typedef struct _FILE_CONTEXT
{
    PVOID shmemMap; // memory mapping of the shared memory
} FILE_CONTEXT, *PFILE_CONTEXT;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FILE_CONTEXT, FileGetContext)

NTSTATUS IVSHMEMCreateDevice(_Inout_ PWDFDEVICE_INIT DeviceInit);

EVT_WDF_DEVICE_PREPARE_HARDWARE IVSHMEMEvtDevicePrepareHardware;
EVT_WDF_DEVICE_RELEASE_HARDWARE IVSHMEMEvtDeviceReleaseHardware;
EVT_WDF_DEVICE_D0_ENTRY IVSHMEMEvtD0Entry;
EVT_WDF_DEVICE_D0_EXIT IVSHMEMEvtD0Exit;
EVT_WDF_INTERRUPT_ISR IVSHMEMInterruptISR;
EVT_WDF_INTERRUPT_DPC IVSHMEMInterruptDPC;

EXTERN_C_END
